﻿/**
 * Stardust Particle Engine
 * 
 * Homepage
 * 	http://code.google.com/p/stardust-particle-engine/
 * 
 * Documentation
 * 	http://stardust-particle-engine.googlecode.com/svn/trunk/docs/index.html
 * 
 * PDF Manual
 * 	http://stardust-particle-engine.googlecode.com/svn/trunk/manual/Stardust%20Particle%20Engine%20Manual.pdf
 */

package {
	import com.bit101.components.PushButton;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import idv.cjcat.stardust.common.clocks.SteadyClock;
	import idv.cjcat.stardust.common.math.StardustMath;
	import idv.cjcat.stardust.threeD.papervision3d.renderers.PV3DDisplayObject3DRenderer;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.core.geom.Lines3D;
	import org.papervision3d.core.geom.renderables.Line3D;
	import org.papervision3d.core.geom.renderables.Vertex3D;
	import org.papervision3d.materials.special.LineMaterial;
	import org.papervision3d.objects.DisplayObject3D;
	import org.papervision3d.render.BasicRenderEngine;
	import org.papervision3d.scenes.Scene3D;
	import org.papervision3d.view.Viewport3D;
	
	[SWF(backgroundColor="#000000", frameRate=60)]
	
	public class Main extends Sprite {
		
		private var pv3dSuperContainer:DisplayObject3D;
		private var pv3dContainer:DisplayObject3D;
		private var pv3dCamera:Camera3D;
		private var pv3dScene:Scene3D;
		private var pv3dViewport:Viewport3D;
		private var pv3dRenderer:BasicRenderEngine;
		
		private var emitter:CubeEmitter;
		
		public function Main():void {
			//PV3D setup
			pv3dSuperContainer = new DisplayObject3D();
			pv3dContainer = new DisplayObject3D();
			pv3dCamera = new Camera3D();
			pv3dCamera.y = 280;
			pv3dScene = new Scene3D();
			pv3dSuperContainer.addChild(pv3dContainer);
			pv3dScene.addChild(pv3dSuperContainer);
			pv3dViewport = new Viewport3D(465, 465);
			addChild(pv3dViewport);
			pv3dRenderer = new BasicRenderEngine();
			
			buildFloor();
			
			//emitter & renderer
			emitter = new CubeEmitter(new SteadyClock(0.25));
			pv3dScene.addChild(emitter.light);
			var renderer:PV3DDisplayObject3DRenderer = new PV3DDisplayObject3DRenderer(pv3dContainer);
			renderer.addEmitter(emitter);
			
			//speed buttons
			var btn0:PushButton = new PushButton(this, 10, 10, "0X", changeSpeed);
			var btn1:PushButton = new PushButton(this, 10, 30, "0.25X", changeSpeed);
			var btn2:PushButton = new PushButton(this, 10, 50, "0.5X", changeSpeed);
			var btn3:PushButton = new PushButton(this, 10, 70, "1X", changeSpeed);
			var btn4:PushButton = new PushButton(this, 10, 90, "2X", changeSpeed);
			var btn5:PushButton = new PushButton(this, 10, 110, "4X", changeSpeed);
			
			addEventListener(Event.ENTER_FRAME, mainLoop);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseRotate);
			mouseRotate();
		}
		
		private function mainLoop(e:Event):void {
			emitter.step();
			pv3dRenderer.renderScene(pv3dScene, pv3dCamera, pv3dViewport);
		}
		
		private function changeSpeed(e:Event):void {
			var btn:PushButton = e.target as PushButton;
			
			if (btn.label == "0X") {
				emitter.actions.active = false;
				emitter.active = false;
				return
			}
			
			emitter.actions.active = true;
			emitter.active = true;
			
			//somehow the "switch" statement causes compile-time error :(
			if (btn.label == "0.25X") emitter.stepTimeInterval = 0.25;
			else if (btn.label == "0.5X") emitter.stepTimeInterval = 0.5;
			else if (btn.label == "1X") emitter.stepTimeInterval = 1;
			else if (btn.label == "2X") emitter.stepTimeInterval = 2;
			else if (btn.label == "4X") emitter.stepTimeInterval = 4;
		}
		
		private function mouseRotate(e:Event = null):void {
			pv3dContainer.rotationY = 0.65 * (232.5 - mouseX);
			pv3dSuperContainer.rotationX = 0.5 * (100 - mouseY);
			pv3dSuperContainer.rotationX = StardustMath.clamp(pv3dSuperContainer.rotationX, -80, 0);
		}
		
		private function buildFloor():void {
			var lineMat:LineMaterial = new LineMaterial(0xA0A0A0, 1);
			var lines:Lines3D = new Lines3D();
			pv3dContainer.addChild(lines);
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( -400, 0, 0), new Vertex3D( 400, 0, 0)));
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( 0, 0, -400), new Vertex3D( 0, 0, 400)));
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( -400, 0, -400), new Vertex3D( 400, 0, -400)));
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( 400, 0, -400), new Vertex3D( 400, 0, 400)));
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( 400, 0, 400), new Vertex3D( -400, 0, 400)));
			lines.addLine(new Line3D(lines, lineMat, 1, new Vertex3D( -400, 0, 400), new Vertex3D( -400, 0, -400)));
		}
	}
}

//------------------------------------------------------------------------------------------------

import flash.display.Shape;
import idv.cjcat.stardust.common.actions.Age;
import idv.cjcat.stardust.common.actions.CompositeAction;
import idv.cjcat.stardust.common.actions.DeathLife;
import idv.cjcat.stardust.common.actions.ScaleCurve;
import idv.cjcat.stardust.common.clocks.Clock;
import idv.cjcat.stardust.common.initializers.Life;
import idv.cjcat.stardust.common.math.UniformRandom;
import idv.cjcat.stardust.threeD.actions.Deflect3D;
import idv.cjcat.stardust.threeD.actions.Gravity3D;
import idv.cjcat.stardust.threeD.actions.Move3D;
import idv.cjcat.stardust.threeD.actions.Spin3D;
import idv.cjcat.stardust.threeD.deflectors.PlaneDeflector;
import idv.cjcat.stardust.threeD.emitters.Emitter3D;
import idv.cjcat.stardust.threeD.fields.UniformField3D;
import idv.cjcat.stardust.threeD.initializers.DisplayObjectClass3D;
import idv.cjcat.stardust.threeD.initializers.Omega3D;
import idv.cjcat.stardust.threeD.initializers.Position3D;
import idv.cjcat.stardust.threeD.initializers.Rotation3D;
import idv.cjcat.stardust.threeD.initializers.Velocity3D;
import idv.cjcat.stardust.threeD.zones.SinglePoint3D;
import idv.cjcat.stardust.threeD.zones.SphereCap;
import org.papervision3d.core.proto.LightObject3D;
import org.papervision3d.materials.shadematerials.FlatShadeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.primitives.Cube;

//------------------------------------------------------------------------------------------------

//I have no idea why this line must be added in order to compile successfully on Wonderfl.
//Just ignore this class :p
class BugFixer extends Shape { public function BugFixer() { } }

//------------------------------------------------------------------------------------------------

class CubeEmitter extends Emitter3D {
	
	public var light:LightObject3D;
	public var actions:CompositeAction;
	
	public function CubeEmitter(clock:Clock) {
		super(clock);
		
		//light & material
		light = new LightObject3D();
		light.y = 600;
		light.z = -1000;
		var mat:FlatShadeMaterial = new FlatShadeMaterial(light, 0x508DC5, 0x224488);
		
		
		//initializers
		var doc3D:DisplayObjectClass3D = new DisplayObjectClass3D();
		doc3D.displayObjectClass = Cube;
		doc3D.constructorParams = [new MaterialsList( { all:mat } ), 40, 40, 40];
		
		var cap:SphereCap = new SphereCap(0, 0, 0, 25, 37.5, 15);
		cap.rotationX = 180;
		
		var rotationRand:UniformRandom = new UniformRandom(0, 180);
		var omegaRand:UniformRandom = new UniformRandom(0, 4);
		
		addInitializer(doc3D);
		addInitializer(new Life(new UniformRandom(200, 0)));
		addInitializer(new Position3D(new SinglePoint3D(0, 0, 0)));
		addInitializer(new Velocity3D(cap));
		addInitializer(new Rotation3D(rotationRand, rotationRand, rotationRand));
		addInitializer(new Omega3D(omegaRand, omegaRand, omegaRand));
		
		
		//actions
		var field:UniformField3D = new UniformField3D(0, -1, 0);
		var gravity:Gravity3D = new Gravity3D();
		gravity.addField(field);
		
		var deflect:Deflect3D = new Deflect3D();
		deflect.addDeflector(new PlaneDeflector(0, 0, 0, 0, 1, 0));
		
		actions = new CompositeAction();
		actions.addAction(gravity);
		actions.addAction(deflect);
		actions.addAction(new Age());
		actions.addAction(new DeathLife());
		actions.addAction(new Move3D());
		actions.addAction(new Spin3D());
		actions.addAction(new ScaleCurve(5, 20));
		
		addAction(actions);
	}
}